#include "OffscreenSurface.hpp"

OffscreenSurface::OffscreenSurface() :
        fbo( 0 ),
        depth( 0 ),
        depthbuffer( 0 )
{
    nextAttachment = GL_COLOR_ATTACHMENT0_EXT;
    m_windowWidth = 512;
    m_windowHeight = 512;
}

void OffscreenSurface::intialize()
{

}

GLuint OffscreenSurface::createDepth()
{
    if( fbo == 0 )
    {
        glGenFramebuffersEXT(1, &fbo);
        assert( glGetError() == GL_NO_ERROR );
    }

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
    assert( glGetError() == GL_NO_ERROR );

    if( depthbuffer == 0 )
    {
        depthbuffer = 1;

        glGenTextures(1, &depth );
        glBindTexture(GL_TEXTURE_2D, depth );
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
        assert( glGetError() == GL_NO_ERROR );
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
        assert( glGetError() == GL_NO_ERROR );
        glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
        assert( glGetError() == GL_NO_ERROR );

        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, m_windowWidth, m_windowHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
        assert( glGetError() == GL_NO_ERROR );
        glBindTexture( GL_TEXTURE_2D, 0 );
        assert( glGetError() == GL_NO_ERROR );

        glDrawBuffer(GL_NONE);
        glReadBuffer(GL_NONE);

        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth, 0 );

        GLenum errCode = glGetError();
        if (errCode != GL_NO_ERROR)
        {
            std::string errString = (const char*)gluErrorString(errCode);
            Logger::write( "OffscreenSurface", "createDepth()", errString.c_str(), Logger::Error );
            assert( errCode == GL_NO_ERROR );
        }

        GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
        assert( status == GL_FRAMEBUFFER_COMPLETE_EXT );

        return depth;
    }

    return 0;
}

GLuint OffscreenSurface::createBuffer()
{
    if( fbo == 0 )
    {
        glGenFramebuffersEXT(1, &fbo);
        assert( glGetError() == GL_NO_ERROR );
    }

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
    assert( glGetError() == GL_NO_ERROR );


    if( depthbuffer == 0 )
    {
        createDepth();
    }

    GLuint img;

    glGenTextures(1, &img);
    glBindTexture(GL_TEXTURE_2D, img);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,  m_windowWidth, m_windowHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glBindTexture(GL_TEXTURE_2D, (GLuint)NULL );
    assert( glGetError() == GL_NO_ERROR );

    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, nextAttachment, GL_TEXTURE_2D, img, 0);
    nextAttachment++;

    GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    assert( status == GL_FRAMEBUFFER_COMPLETE_EXT );

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint)NULL );
    assert( glGetError() == GL_NO_ERROR );



    return img;
}


void OffscreenSurface::bind()
{
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);

    GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    assert( status == GL_FRAMEBUFFER_COMPLETE_EXT );

//	glPushAttrib( GL_VIEWPORT_BIT );
//	glViewport(0, 0, m_windowWidth, m_windowHeight );
//	assert( glGetError() == GL_NO_ERROR );
}


void OffscreenSurface::unbind()
{
//	glPopAttrib( );
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    assert( glGetError() == GL_NO_ERROR );
}



